package com.credithc.signature.manager.service;

import cfca.seal.bean.CertApplyInfoBean;
import cfca.seal.bean.SealInfoBean;
import cfca.seal.servlet.SealClient;
import cfca.seal.util.StrategyUtil;
import cfca.seal.util.StringUtil;
import com.credithc.baseserv.core.message.Message;
import com.credithc.signature.common.constant.ManagerConstant;
import com.credithc.signature.common.constant.SealConstant;
import com.credithc.signature.common.mapper.CertMapper;
import com.credithc.signature.common.mapper.FddSealInfoMapper;
import com.credithc.signature.common.mapper.SealChannelMapper;
import com.credithc.signature.common.mapper.SealInfoMapper;
import com.credithc.signature.common.po.Cert;
import com.credithc.signature.common.po.Channel;
import com.credithc.signature.common.po.FddConfig;
import com.credithc.signature.common.po.FddSealInfo;
import com.credithc.signature.common.po.OfficialSealTemplate;
import com.credithc.signature.common.po.SealChannel;
import com.credithc.signature.common.po.SealInfo;
import com.credithc.signature.common.po.Template;
import com.credithc.signature.common.ro.manager.SealInfoRo;
import com.credithc.signature.common.service.*;
import com.credithc.signature.common.service.lanmao.LanmaoRegisterService;
import com.credithc.signature.common.utils.ErrorCodeHelper;
import com.credithc.signature.common.utils.FddConfigMap;
import com.credithc.signature.common.utils.ManagerBeanUtil;
import com.credithc.signature.common.utils.TimeUtil;
import com.credithc.signature.common.utils.UUIDUtil;
import com.credithc.signature.manager.client.AuthClient;
import com.credithc.signature.manager.ro.TokenRo;
import com.credithc.signature.manager.utils.FileUploadUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class CfcaSealService {

    @Value("${signature.cfca.sealUrl}")
    private String host;

    @Autowired
    SealInfoService sealInfoService;

    @Autowired
    SealInfoMapper sealInfoMapper;

    @Autowired
    FddSealInfoMapper fddSealInfoMapper;

    @Autowired
    CertInfoService certInfoService;

    @Autowired
    AuthClient authClient;

    @Autowired
    DictionaryService dictionaryService;

    @Autowired
    SealChannelMapper sealChannelMapper;

    @Autowired
    SealChannelService sealChannelService;

    @Autowired
    LanmaoRegisterService lanmaoRegisterService;

    @Autowired
    OfficialSealTemplateService officialSealTemplateService;

    @Autowired
    ChannelService channelService;

    @Autowired
    TemplateService templateService;

    @Autowired
    CertMapper certMapper;

    /**
     * 自动化制章--(公章)
     *
     * @param sealInfoRo
     */
    public String makeSealAutomation(SealInfoRo sealInfoRo) throws Exception {
        String sealOrg = sealInfoRo.getSealOrg();
        if (SealConstant.ADMINISTRATIVE_SEAL.equals(sealInfoRo.getUseType()) && !sealOrg.contains("-行政")) {
            sealOrg = sealOrg + "-行政";
            sealInfoRo.setSealOrg(sealOrg);
        }
        String sealName = sealInfoRo.getSealOrg();
        String imageCode = "IMG_" + UUIDUtil.getRandomFixedLengthCode(8);
        String sealCode = null;
        if (StringUtils.isNotBlank(sealInfoRo.getSealCode())) {
            sealCode = sealInfoRo.getSealCode();
        } else {
            sealCode = "OFFICE_" + UUIDUtil.getRandomFixedLengthCode(8);
        }

        String sealPwd = UUIDUtil.getRandomFixedLengthCode(10);
        String identificationNo = sealInfoRo.getIdentificationNo();
        String identificationType = sealInfoRo.getIdentificationType();
        String sealImageSize = sealInfoRo.getSealImageSize();

        //封装证书参数
        CertApplyInfoBean certApplyInfoBean = new CertApplyInfoBean(SealConstant.CUSTOMER_TYPE, SealConstant.KEY_ALG, SealConstant.KEY_LENGTH, SealConstant.SEAL_PERSON, identificationType, identificationNo);
        //封装公章参数
        SealInfoBean sealInfoBean = new SealInfoBean(SealConstant.SEAL_PERSON, sealOrg, sealName, sealCode, sealPwd, SealConstant.SEAL_TYPE, imageCode, SealConstant.ORG_CODE, SealConstant.SEAL_FLAG);

        byte[] image = FileUploadUtil.downloadImg(sealInfoRo.getPictureId());

        // 新版本的SealClient的地址需要加上 SealClient.SLASH + SealClient.MAKE_SEAL_SERVLET
        SealClient client = new SealClient(host + SealClient.SLASH + SealClient.MAKE_SEAL_SERVLET);
        //如果公章主体信息相同，则需要重新设置SEAL_FLAG的值，不然会报 印章申请信息（证件类型-证件号-印章标识）重复 的错误
        sealInfoBean.setSealFlag(UUIDUtil.getRandomFixedLengthCode(2));
        sealInfoBean.setSealImageSize(sealImageSize);

        //保存公章、证书信息
        saveDB(sealInfoRo, sealInfoBean, image);

        String certApplyXML = StrategyUtil.createCertApplyXml(certApplyInfoBean);
        String sealInfoXML = StrategyUtil.creatSealInfoXML(sealInfoBean);
        String result = client.makeSealAutomation(certApplyXML, image, sealInfoXML);
        log.info("自动化制公章返回结果：result=" + result);

        if (SealConstant.SUCCESS.equals(StringUtil.getNodeText(result, SealConstant.RETURNCODE))) {
            log.info("MakeSealAutomation(WebService):ok");
            updateCertInfo(client, sealCode);
            updateSealInfo(sealCode, ManagerConstant.SEAL_SUCCESS, ManagerConstant.Enable);
            updateTmpleateSealInfo(sealCode, sealInfoRo);
            //懒猫制公章
//            lanmaoRegisterService.registerEnt(sealCode);
            return "SUCCESS";
        } else {
            log.info("MakeSealAutomation(WebService):wrong");
            deleteSealInfo(sealCode);
            return ErrorCodeHelper.parseErrorCode(StringUtil.getNodeText(result, SealConstant.RETURNCODE), StringUtil.getNodeText(result, SealConstant.RETURNMSG));
        }
    }

    /**
     * 关联模板和公章
     *
     * @param sealCode
     * @param sealInfoRo
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void updateTmpleateSealInfo(String sealCode, SealInfoRo sealInfoRo) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Message<TokenRo> tokenRo = authClient.getUserInfoByToken(request.getHeader("token"));
        log.info("数据权限查询结果:" + tokenRo.toString());
        if (tokenRo.getData() != null) {
            TokenRo data = tokenRo.getData();
            String productCode = data.getProductCode();
            Channel channel = channelService.selectByChannelNo(productCode);
            Integer id = channel.getId();
            List<Template> templates = templateService.queryListBychannelId(id);
            templates.stream().forEach(p -> {
                Integer sealType = p.getSealType();
                String relateSealCode = sealInfoRo.getRelateSealCode();
                if (!sealType.equals(1) && "1".equals(relateSealCode)) {
                    OfficialSealTemplate sealTemplate = new OfficialSealTemplate();
                    sealTemplate.setOfficialSealCode(sealCode);
                    sealTemplate.setTemplateNo(p.getTemplateNo());
                    officialSealTemplateService.insert(sealTemplate);
                }
            });
        }
    }

    /**
     * 保存到数据库
     *
     * @param sealInfoRo
     * @param sealInfoBean
     * @param image
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void saveDB(SealInfoRo sealInfoRo, SealInfoBean sealInfoBean, byte[] image) {
        //保存证书信息
        Long certId = saveCert();
        //保存公章信息
        saveSealInfo(certId, sealInfoRo, sealInfoBean, image);
        //保存公章渠道关联表
        saveSealChannelInfo(sealInfoBean);
    }

    /**
     * 保存公章渠道关联表
     *
     * @param sealInfoBean
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void saveSealChannelInfo(SealInfoBean sealInfoBean) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Message<TokenRo> tokenRo = authClient.getUserInfoByToken(request.getHeader("token"));
        log.info("数据权限查询结果:" + tokenRo.toString());
        if (tokenRo.getData() != null) {
            TokenRo data = tokenRo.getData();
            SealChannel sealChannel = new SealChannel();
            sealChannel.setChannelNo(data.getProductCode());
            sealChannel.setSealCode(sealInfoBean.getSealCode());
            sealChannel.setStatus(ManagerConstant.Enable);
            sealChannelMapper.insert(sealChannel);
        }
    }

    /**
     * 保存证书信息
     *
     * @return
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public Long saveCert() {
        Cert cert = new Cert();
        cert.setApplyTime(new Date());
        cert.setExpireTime(TimeUtil.getExpireTime(1));
        cert.setCreateTime(new Date());
        cert.setUpdateTime(new Date());
        certInfoService.insertAndGetId(cert);
        return cert.getId();
    }

    /**
     * 保存公章信息
     *
     * @param certId
     * @param sealInfoRo
     * @param sealInfoBean
     * @param image
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void saveSealInfo(Long certId, SealInfoRo sealInfoRo, SealInfoBean sealInfoBean, byte[] image) {
        SealInfo sealInfo = new SealInfo();
        sealInfo.setSealType(ManagerConstant.SEAL_ENTERPRISE);
        sealInfo.setSealCode(sealInfoBean.getSealCode());
        sealInfo.setSealPwd(sealInfoBean.getSealPassword());
        sealInfo.setCertId(certId.intValue());
        sealInfo.setSealPerson(sealInfoBean.getSealPerson());
        sealInfo.setSealOrg(sealInfoBean.getSealOrg());
        sealInfo.setSealName(sealInfoBean.getSealName());
        sealInfo.setCustomerType(ManagerConstant.SEAL_ENTERPRISE);
        sealInfo.setIdentificationType(sealInfoRo.getIdentificationType());
        sealInfo.setIdentificationNo(sealInfoRo.getIdentificationNo());
        sealInfo.setSealStatus(ManagerConstant.SEAL_UNDO);
        sealInfo.setLifePeriod(1);
        sealInfo.setImage(image);
        sealInfo.setSealSource(SealConstant.SEALSOURCE_ZJ);
        sealInfo.setExt1(sealInfoBean.getImageCode());
        sealInfo.setExt2(sealInfoBean.getSealImageSize());
        sealInfo.setKeyWords(sealInfoRo.getKeyWords());
        sealInfo.setStatus(ManagerConstant.Enable);
        sealInfo.setOfficeSealType(sealInfoRo.getOfficeSealType());
        sealInfo.setUseType(sealInfoRo.getUseType());
        sealInfo.setCreateTime(new Date());
        sealInfo.setUpdateTime(new Date());

        sealInfo.setLegalPersonId(sealInfoRo.getLegalPersonId());
        sealInfo.setLegalPersonCardType(sealInfoRo.getLegalPersonCardType());
        sealInfo.setLegalPersonName(sealInfoRo.getLegalPersonName());
        sealInfo.setPhone(sealInfoRo.getPhone());
        sealInfo.setContactPhone(sealInfoRo.getContactPhone());

        sealInfoService.insert(sealInfo);
    }

    /**
     * 更新制章信息
     *
     * @param sealCode
     * @param sealStatus
     * @param status
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void updateSealInfo(String sealCode, Integer sealStatus, Integer status) {
        try {
            SealInfo info = sealInfoService.selectBySealCode(sealCode);
            if (info != null) {
                info.setSealStatus(sealStatus);
                info.setStatus(status);
                sealInfoService.updateByPrimaryKeySelective(info);
                //更新sealChannel状态
                SealChannel sealChannel = new SealChannel();
                sealChannel.setSealCode(sealCode);
                SealChannel sealChannelPo = sealChannelMapper.selectOne(sealChannel);
                sealChannelPo.setStatus(ManagerConstant.Enable);
                sealChannelMapper.updateByPrimaryKey(sealChannelPo);
                log.info("更新公章信息成功......");
            }
        } catch (Exception e) {
            log.info("更新公章信息失败......", e);
        }
    }

    /**
     * 删除制章信息
     *
     * @param sealCode
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void deleteSealInfo(String sealCode) {
        certInfoService.deleteBySealCode(sealCode);
        sealChannelService.deleteBySealCode(sealCode);
        sealInfoService.deleteBySealCode(sealCode);
    }

    /**
     * 更新证书信息
     *
     * @param client
     * @param sealCode
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void updateCertInfo(SealClient client, String sealCode) {
        try {
            String result = client.getSealInfo(sealCode);
            SealInfo info = sealInfoService.selectBySealCode(sealCode);
            if (SealConstant.SUCCESS.equals(StringUtil.getNodeText(result, SealConstant.RETURNCODE))) {
                log.info("GetSealInfoTest(WebService):ok");
                String certDN = StringUtil.getNodeText(result, SealConstant.CertDN);
                String certSN = StringUtil.getNodeText(result, SealConstant.CertSN);
                Integer certId = info.getCertId();
                Cert cert = new Cert();
                cert.setUpdateTime(new Date());
                cert.setCertDn(certDN);
                cert.setCertSn(certSN);
                cert.setId(Long.valueOf(certId));
                certMapper.updateByPrimaryKeySelective(cert);
                log.info("更新证书信息成功......");
            } else {
                log.info("GetSealInfoTest(WebService):wrong");
            }
        } catch (Exception e) {
            log.info("获取证书信息发生异常......", e);
        }
    }

    /**
     * 根据证件类型证件号码查询唯一(中金)
     *
     * @param sealInfoRo
     * @return
     */
    public SealInfo queryOne(SealInfoRo sealInfoRo) {
        SealInfo sealInfo = new SealInfo();
        sealInfo.setIdentificationType(sealInfoRo.getIdentificationType());
        sealInfo.setIdentificationNo(sealInfoRo.getIdentificationNo());
        sealInfo.setOfficeSealType(sealInfoRo.getOfficeSealType());
        sealInfo.setUseType(sealInfoRo.getUseType());
        sealInfo.setSealSource(sealInfoRo.getSealSource());
        Map<String, Object> params = ManagerBeanUtil.buildQueryParams(sealInfo);
        return sealInfoMapper.selectOneByExample(params.get(ManagerConstant.EXAMPLE));
    }

    /**
     * 根据证件类型证件号码查询唯一(法大大)
     *
     * @param sealInfoRo
     * @return
     */
    public FddSealInfo queryOne2(SealInfoRo sealInfoRo) {
        FddSealInfo sealInfo = new FddSealInfo();
        sealInfo.setIdentificationType(sealInfoRo.getIdentificationType());
        sealInfo.setIdentificationNo(sealInfoRo.getIdentificationNo());
        sealInfo.setSealSource(sealInfoRo.getSealSource());
        sealInfo.setAppId(sealInfoRo.getAppId());
        Map<String, Object> params = ManagerBeanUtil.buildQueryParams(sealInfo);
        return fddSealInfoMapper.selectOneByExample(params.get(ManagerConstant.EXAMPLE));
    }

    /**
     * 保存到sealChannel关联表
     *
     * @param sealCode
     * @param channelNo
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void saveSealChannelInfo(String sealCode, String channelNo) {
        SealChannel sealChannel = new SealChannel();
        sealChannel.setChannelNo(channelNo);
        sealChannel.setSealCode(sealCode);
        if (sealChannelMapper.selectCount(sealChannel) <= 0) {
            sealChannel.setStatus(ManagerConstant.Enable);
            sealChannelMapper.insert(sealChannel);
        }
    }

    /**
     * 本地制章--中金
     *
     * @param sealInfoRo
     * @param request
     * @return
     */
    public String makeSealInLocal(SealInfoRo sealInfoRo, HttpServletRequest request) {
        Message<TokenRo> tokenRo = authClient.getUserInfoByToken(request.getHeader("token"));
        log.info("数据权限查询结果:" + tokenRo.toString());
        if (tokenRo.getData() != null) {
            String sealCode = sealInfoRo.getSealCode();
            TokenRo data = tokenRo.getData();
            String productCode = data.getProductCode();
            //如果此记录不存在则保存
            SealChannel sealChannel = new SealChannel();
            sealChannel.setSealCode(sealCode);
            sealChannel.setChannelNo(productCode);
            int count = sealChannelMapper.selectCount(sealChannel);
            if (count > 0) {
                log.info("本地制公章失败......" + SealConstant.RETURNMSG1);
                return SealConstant.RETURNMSG1;
            } else if (StringUtils.isEmpty(productCode)) {
                log.info("本地制公章失败......" + SealConstant.RETURNMSG2);
                return SealConstant.RETURNMSG2;
            } else if (StringUtils.isEmpty(sealCode)) {
                log.info("本地制公章失败......" + SealConstant.RETURNMSG3);
                return SealConstant.RETURNMSG3;
            } else {
                this.saveSealChannelInfo(sealCode, productCode);
                log.info("本地制公章成功......");
                return "SUCCESS";
            }
        } else {
            log.info("本地制公章失败......");
            return SealConstant.RETURNMSG2;
        }
    }

    /**
     * 本地制章--法大大
     *
     * @param sealInfoRo
     * @param request
     * @return
     */
    public String makeSealInLocal2(SealInfoRo sealInfoRo, HttpServletRequest request) {
        Message<TokenRo> tokenRo = authClient.getUserInfoByToken(request.getHeader("token"));
        log.info("数据权限查询结果:" + tokenRo.toString());
        if (tokenRo.getData() != null) {
            String sealCode = sealInfoRo.getSealCode();
            TokenRo data = tokenRo.getData();
            String productCode = data.getProductCode();
            //如果此记录不存在则保存
            SealChannel sealChannel = new SealChannel();
            sealChannel.setSealCode(sealCode);
            sealChannel.setChannelNo(productCode);
            int count = sealChannelMapper.selectCount(sealChannel);
            if (count > 0) {
                log.info("本地制公章失败......" + SealConstant.RETURNMSG1);
                return SealConstant.RETURNMSG1;
            } else if (StringUtils.isEmpty(productCode)) {
                log.info("本地制公章失败......" + SealConstant.RETURNMSG2);
                return SealConstant.RETURNMSG2;
            } else if (StringUtils.isEmpty(sealCode)) {
                log.info("本地制公章失败......" + SealConstant.RETURNMSG3);
                return SealConstant.RETURNMSG3;
            } else {
                String channelNo = sealInfoRo.getChannelNo();
                // 获取appID
                FddConfig fddConfig = FddConfigMap.getConfig().get(channelNo);
                String appId = fddConfig.getAppId();
                // 查询是公章否存在
                FddSealInfo sealInfoParams = new FddSealInfo();
                sealInfoParams.setAppId(appId);
                sealInfoParams.setSealCode(sealCode);
                sealInfoParams.setSealSource(SealConstant.SEALSOURCE_FDD);
                Map<String, Object> params = ManagerBeanUtil.buildQueryParams(sealInfoParams);
                FddSealInfo fddSealInfo = fddSealInfoMapper.selectOneByExample(params.get(ManagerConstant.EXAMPLE));
                if (fddSealInfo != null) {
                    this.saveSealChannelInfo(sealCode, productCode);
                    log.info("本地制公章成功......");
                    return "SUCCESS";
                } else {
                    log.info("本地制公章失败......" + SealConstant.RETURNMSG4);
                    return SealConstant.RETURNMSG4;
                }
            }
        } else {
            log.info("本地制公章失败......");
            return SealConstant.RETURNMSG2;
        }
    }
}
